﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESoft.AspNetCore.DTO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;

namespace ESoft.AspNetCore.Authentication
{
    /// <summary>
    /// 前台登录验证
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    class CookieAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        private readonly IConfiguration _configuration;

        public CookieAuthorizeAttribute(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public virtual void OnAuthorization(AuthorizationFilterContext filterContext)
        {
            var authenticate = filterContext.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationSchema);
            if (authenticate.Result.Succeeded || this.SkipUserAuthorize(filterContext.ActionDescriptor))
            {
                return;
            }

            var httpRequest = filterContext.HttpContext.Request;

            if (GetUri(httpRequest).AbsoluteUri.Contains("/api"))
            {
                filterContext.Result = new JsonResult(ResponseResult.FailOut(ResponseResult.LOGIN_TIME_OUT, new Exception("登陆信息已过期，请重新登录！")));
            }
            else
            {
                string url = string.Concat(_configuration["siginUrl"], "?returnUrl=", httpRequest.Path);
                RedirectResult redirectResult = new RedirectResult(url);
                filterContext.Result = redirectResult;
            }
        }

        private Uri GetUri(HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (string.IsNullOrWhiteSpace(request.Scheme))
            {
                throw new ArgumentException("Http request Scheme is not specified");
            }
            if (!request.Host.HasValue)
            {
                throw new ArgumentException("Http request Host is not specified");
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(request.Scheme).Append("://").Append(request.Host);
            if (request.Path.HasValue)
            {
                stringBuilder.Append(request.Path.Value);
            }
            if (request.QueryString.HasValue)
            {
                stringBuilder.Append(request.QueryString);
            }
            return new Uri(stringBuilder.ToString());
        }

        protected virtual bool SkipUserAuthorize(ActionDescriptor actionDescriptor)
        {
            bool skipAuthorize = actionDescriptor.FilterDescriptors.Any(a =>
                a.Filter is AllowAnonymousFilter);
            return skipAuthorize;
        }
    }
}
